package com.kx.game.center.dbs;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import com.kx.game.center.global.GSServices;

import javax.sql.DataSource;

import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import com.genchance.core.dawn.global.ConstantData;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DBServices {

    private static Logger logger = LoggerFactory.getLogger(DBServices.class);

    /**
     * 数据库c3p0配置文件路径
     */
    public static String db_pool_Config = "db.properties";

    /**
     * 数据库SQL配置文件地址
     */
    public static String sql_Config = "dbconfig.xml";

    /**
     * 数据连接器
     */
    public static Map<String, SqlSessionFactory> dbSessionFactorys = new HashMap<>();

    public static String myServerId = "0.0.0.0";

    public static String friendServerId = "100";

    /**
     * 返回数据库连接操作的session
     * <p>
     * 注意：用完后调用sqlSession.close();关闭连接
     * <p>
     *
     * @return 数据库管理器
     */
    public static SqlSession getDBConntion(String index) {
        return dbSessionFactorys.get(index).openSession(true);
    }

    public static Map<String, SqlSessionFactory> getDbSessionFactorys() {
        return dbSessionFactorys;
    }

    public DBServices() {
        createDB();
        dbSessionFactorys.put(myServerId, this.init(DBServices.sql_Config, ConstantData.configPath + DBServices.db_pool_Config, "", ""));
    }

    /**
     * 初始化连接Session
     *
     * @return 连接Session
     */
    public SqlSessionFactory init(String sql_Config, String c3p0_Config, String ip, String port) {
        SqlSessionFactory sqlSessionFactory = null;
        Reader reader = null;
        InputStream in = null;
        try {
            // in = new FileInputStream(sql_Config);
            in = this.getClass().getClassLoader().getResourceAsStream(sql_Config);
            reader = new InputStreamReader(in, "UTF-8");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            // 获取原配置的Configuration
            Configuration configuration = sqlSessionFactory.getConfiguration();
            // 获取c3p0数据源
            DataSource dataSource = this.getDataSource(c3p0_Config, ip, port);
            // 重新配置环境
            Environment environment = new Environment("product", new JdbcTransactionFactory(), dataSource);
            // 设置新的设置环境
            configuration.setEnvironment(environment);
            // 重新构建连接工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
            return sqlSessionFactory;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Can not open resource!", e);
            System.exit(0);
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                    reader = null;
                }

                if (in != null) {
                    in.close();
                    in = null;
                }
            } catch (IOException e) {
            }
        }
        return sqlSessionFactory;
    }

    /**
     * 获取c3p0连接
     *
     * @param path c3p0的配置文件路径
     * @return 返回c3p0的数据源
     * @throws Exception 向上抛出错误
     */
    private ComboPooledDataSource getDataSource(String path, String ip, String port) throws Exception {
        // 设置连接参数
        Properties prop = new Properties();
        InputStream in = null;
        Reader re = null;
        try {
            logger.info("load file :" + path);
            in = new FileInputStream(path);
            re = new InputStreamReader(in, "UTF-8");
            prop.load(re);
            String jdbcUrl = String.valueOf(prop.getProperty("jdbcUrl"));
            String user = String.valueOf(prop.getProperty("user"));
            String password = String.valueOf(prop.getProperty("password"));
            if (ip != null && !ip.equals("")) {
                jdbcUrl = jdbcUrl.replace("127.0.0.1", ip);
                user = user.replace("root", "gmroot");
                jdbcUrl = jdbcUrl.replace("3306", port);
                jdbcUrl = jdbcUrl.replace("game_center", GSServices.serverConfig.getGameDBname());
            }
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(String.valueOf(prop.getProperty("driverClass")));
            dataSource.setJdbcUrl(jdbcUrl);
            dataSource.setUser(user);
            dataSource.setPassword(password);
            dataSource.setInitialPoolSize(Integer.parseInt(String.valueOf(prop.getProperty("initialPoolSize"))));
            dataSource.setMaxPoolSize(Integer.parseInt(String.valueOf(prop.getProperty("maxPoolSize"))));
            dataSource.setMinPoolSize(Integer.parseInt(String.valueOf(prop.getProperty("minPoolSize"))));
            dataSource.setAcquireIncrement(Integer.parseInt(String.valueOf(prop.getProperty("acquireIncrement"))));
            dataSource.setAutoCommitOnClose(Boolean.getBoolean(String.valueOf(prop.get("autoCommitOnClose"))));
            return dataSource;
        } finally {
            if (re != null) {
                re.close();
                re = null;
            }
            if (in != null) {
                in.close();
                in = null;
            }
        }
    }

    /**
     * 创建数据库，连接上默认的mysql库，以它为跳板创建我们需要的数据库
     */
    public void createDB() {
        // 执行脚本
        Properties prop = new Properties();
        InputStream in = null;
        Reader re = null;
        String dbName = null;
        String driverClass = null;
        String user = null;
        String password = null;
        String jdbcUrl = null;
        try {
            in = new FileInputStream(ConstantData.configPath
                    + DBServices.db_pool_Config);
            logger.info("createDB load file :" + ConstantData.configPath
                    + DBServices.db_pool_Config);
            re = new InputStreamReader(in, "UTF-8");
            prop.load(re);
            jdbcUrl = String.valueOf(prop.getProperty("jdbcUrl"));
            int start = jdbcUrl.lastIndexOf("/");
            int end = jdbcUrl.indexOf("?");
            if (start >= end || start == -1 || end == -1) {
                throw new IllegalArgumentException(
                        "Can't found dbName from jdbcUrl");
            } else {
                dbName = jdbcUrl.substring(start + 1, end);
            }
            driverClass = String.valueOf(prop.getProperty("driverClass"));
            jdbcUrl = String.valueOf(prop.getProperty("tmpJdbcUrl"));
            user = String.valueOf(prop.getProperty("user"));
            password = String.valueOf(prop.getProperty("password"));
        } catch (Exception e) {
            logger.error("Can't found dbName", e);
            System.exit(0);
        } finally {
            if (re != null) {
                try {
                    re.close();
                } catch (IOException e) {
                }
                re = null;
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
                in = null;
            }
        }
        String sql = "CREATE DATABASE IF NOT EXISTS " + dbName
                + " DEFAULT CHARACTER SET utf8";
        Connection conn = null;
        Statement statement = null;
        try {
            Driver driver = (Driver) Class.forName(driverClass).newInstance();
            DriverManager.registerDriver(driver);
            conn = DriverManager.getConnection(jdbcUrl, user, password);
            statement = conn.createStatement();
            statement.execute(sql);
        } catch (Exception e) {
            logger.error("create DataBase failure !!", e);
            System.exit(0);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                    statement = null;
                }
            } catch (SQLException e) {
            }
            try {
                if (conn != null) {
                    conn.close();
                    conn = null;
                }
            } catch (SQLException e) {
            }
        }
    }

    public void update(String serverId, String... sqls) {
        SqlSession session = null;
        try {
            session = getDBConntion(serverId);
            String sql = "update " + sqls[0] + " set " + sqls[1];
            logger.info("执行sql " + sql);
            session.update("Base_Info" + ".defined", sql);
            logger.info("ok " + sql);
        } finally {
            session.close();
        }
    }

    public void delete(String serverId, String... sqls) {
        SqlSession session = null;
        try {
            session = getDBConntion(serverId);
            String sql = "drop table " + sqls[0];
            logger.info("执行sql " + sql);
            session.update("Base_Info" + ".defined", sql);
            logger.info("ok " + sql);
        } finally {
            session.close();
        }
    }

    public void defined(String serverId, String sql) {
        SqlSession session = null;
        try {
            session = getDBConntion(serverId);
            logger.info("执行sql " + sql);
            session.update("Base_Info" + ".defined", sql);
            logger.info("ok " + sql);
        } finally {
            session.close();
        }
    }

}
